#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>

/* This function sets the environment for
 * setjmp()/longjmp().
 * It works only if it is called from a
 * function that it calls itself. After
 * a return, the stack is reduced again
 * and the environment doesn't fit anymore.
 */
int backToHere(char *s, jmp_buf env)
{
    //first call will work with return 0
    int i = setjmp(env);
    
    //print return value of setjmp()
    printf("Returned from setjmp() with %d\n", i);

    //will work in the first call
    //will crash in the second call as the stack has changed
    printf("s = %s\n", s);
    return i;
}

/* This function provides the longjmp() to 
 * backToHere(). As it is called by main()
 * and backToHere() has returned before,
 * the longjmp() behaves unpredictable.
 */
int wantBack(int i, jmp_buf env)
{
    printf("Now I want to go back.\n");
    longjmp(env, i);
}

/* The main program call backToHere() first.
 * After this has returned, wantBack() is called.
 * -> Segmentation fault!
 */
int main()
{
    //buffer for setjmp()/longjmp()
    //stores registers
    jmp_buf env;

    //call backToHere()
    if(backToHere("Hello World", env) != 0)
	exit(0);
    //after return of backToHere() call wantBack()
    wantBack(3, env);
}

/*---------------------------------------------------------------------------
 * STACK
 * -----------------------------------------------
 * 
 * 
 *             <- sp
 * env[0]
 * env[1]
 * env[2]
 * env[3]
 * ...
 * env[last]
 * ...         <- bp
 * -----------------------------------------------
 *
 * main routine calls backToHere():
 * STACK
 * -----------------------------------------------
 * 
 *
 *             <- sp, bp
 * old bp ----------------------------
 * old pc                             |
 * s = "whatever" (pointer to heap)   |
 * pointer to env-                    |
 * env[0]      <-|                    |
 * ...                                |
 * env[last]                          | 
 * ...           <--------------------
 * -----------------------------------------------
 *
 * backToHere() starts running:
 * STACK
 * -----------------------------------------------
 *             <- sp
 * i           <- bp
 * old bp      
 * old pc
 * s="whatever" (pointer to heap)
 * pointer to env-
 * env[0]      <-|
 * ...
 * env[last]
 * ...
 * -----------------------------------------------
 * 
 * setjmp() is called
 * current registers are saved, especially bp, pc, sp
 * function returns to main:
 * STACK
 * -----------------------------------------------
 * 
 * 
 *             <- sp
 * env[0]
 * env[1]
 * env[2]
 * env[3]
 * ...
 * env[last]
 * ...         <- bp
 * -----------------------------------------------
 * 
 * wantBack() is called:
 * STACK
 * -----------------------------------------------
 *             <- sp,bp
 * old bp ----------------------------
 * old pc                             |
 * i=3                                |
 * pointer to env-                    |
 * env[0]      <-|                    |
 * ...                                |
 * env[last]                          |
 * ...           <--------------------
 * -----------------------------------------------
 *
 * now longjmp is called
 * the registers are restored to
 * their old values:
 * STACK
 * -----------------------------------------------
 *              <- sp
 * i = 3        <- bp
 * old bp ---------------------------
 * old pc                            |
 * i=3(pointer to s on heap expected)|
 * pointer to env-                   |
 * env[0]      <-|                   |
 * ...                               |
 * env[last]                         |
 * ...         <---------------------
 * -----------------------------------------------
 * 
 * s is expected to be a pointer to heap where s lies
 * -> segmentation fault
 */
 
